Java基础知识(三)

Author Avatar
子语 2017 - 10 - 02
  • 在其它设备中阅读本文章

方法的定义与使用

方法的基本概念

  1. 方法就是将一段可重复使用的代码封装。因此如要反复执行一段代码时,可考虑将这段代码定义为方法。本章中的方法指的是定义在主类中,由主方法直接调用的方法。此类方法的语法:
public static 返回值类型 method_name(v_type v1, v_type v2,...) {
    方法体; // 方法要进行的若干操作
    [return [返回值] ;] // []中内容可写可不写
}

返回值类型:

数据类型(基本数据类型、引用数据类型) 无返回值(void)
如果方法设置了返回值类型,那么必须使用return返回与之类型对应的内容 不需要return语句,但可用return结束方法调用
  1. 方法名的命名规则:第一个单词小写,随后每个单词首字母大写
    范例:定义无参无返回值方法
package com.java.demo;
public class Demo {
    public static void main(String[] args) {
        print(); // 直接调用
    }
    public static void print(){
        System.out.println("无参无返回值方法");
    }
}

范例:定义含参无返回值方法

package com.java.demo;
public class Demo {
    public static void main(String[] args) {
        compare(10.2); // 调用时必须写入参数
        compare(-10.2);
    }

    public static void compare(double x){
        String str = x > 0.0 ? "这是正数":"这是负数";
        System.out.println(str);
    }
}

有了参数后,方法就可以根据不同的参数内容进行数据的处理。
范例:定义含参数有返回值方法

package com.java.demo;
public class Demo {
    public static void main(String[] args) {
        //定义变量接收返回值,而后输出
        int result = add(10, 20);
        System.out.println(result);
        // 直接输出返回值
        System.out.println(add(10, 20));
    }

    public static int add(int x, int y) {
        return x + y;
    }
}
  1. 一个方法使用void定义,该方法无法使用return返回值,但可以使用return结束调用。
package com.java.demo;
public class Demo {
    public static void main(String[] args) {
        print(1100); // x = 1100
        print(3); // 结束调用,不输出x
    }

    public static void print(int x) {
        if (x == 3) {
            System.out.println("结束调用,不输出x");
            return;
        }
        System.out.println("x = " + x);
    }
}

只有返回值类型为void时,才可使用return结束方法的调用。

方法重载

  1. 假设add()要执行两个整数相加,也要执行三个整数相加和两个小数相加,此时一个方法体无法实现所有功能,但又不能定义其他方法,就需要为add()定义不同的功能实现,该操作就称为方法重载(overloading)
  2. 方法重载要求方法名一致,参数类型或个数不同
package com.java.demo;
public class Demo {
    public static void main(String[] args) {
        // 根据参数的个数或类型,调用不同方法
        add(10,20);
        add(10.2,20.2);
        add(10,20,30);
    }
    // 方法名相同,参数的类型或个数不同
    public static void add(int x, int y) {
        System.out.println("两个整数相加:" + (x + y));
    }

    public static void add(double x, double y) {
        System.out.println("两个小数相加:" + (x + y));
    }

    public static void add(int x, int y, int z) {
        System.out.println("三个整数相加:" + (x + y + z));
    }
}

System.out.println()可以输出不同类型数据,可知此方法是一个被重载后的方法。

  1. 方法重载的说明:
    (1)虽然重载后的方法的返回值类型可以不同,但建议方法重载时返回值类型应一致;
    (2)方法重载是根据参数类型或个数的不同来区分调用,而不是根据返回值类型。
package com.java.demo;
public class Demo {
    public static void main(String[] args) {
    }
    // 报错,已在类中定义了方法 add(int,int)
    // 说明方法重载的依据是参数的个数或类型不同,而不是返回值类型不同
    public static int add(int x, int y) {
        return x + y;
    }

    public static double add(int x, int y) {
        return x + y;
    }
}

递归调用

  1. 递归调用是指方法调用自身。要实现递归调用,要有结束条件。递归调用应尽量少使用,因为处理不当会出现内存溢出。
    范例:递归实现1~100的累加操作
package com.java.demo;
public class Demo {
    public static void main(String[] args) {
        System.out.println(sum(100));
    }
    public static int sum(int num){
        if (num == 1) { // 结束递归调用
            return 1;
        }
        // 递归调用
        return num + sum(num - 1); 
    }
}

代码的执行步骤:

No. 内容 返回值
1 主方法调用sum(100) 100+sum(99)
2 递归调用sum(99) 100 + 99 + sum(98)
3 递归调用sum(98) 100 + 99 + 98+ sum(97)
依此类推
最后一次 递归调用sum(1) sum=100+99+98+…+2+1,结束递归

类与对象

面向对象简介

面向过程:指的是针对某一个问题单独提出解决方案和代码开发。
面向对象:以组件化的形式进行代码设计,优点是代码可重用。
面向对象语言的特征:
(1)封装性:保护内部结构安全性。
(2)继承性:在已有的程序结构上扩充新的功能。
(3)多态性:相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果
面向对象开发步骤:OOA(面向对象分析),OOD(面向对象设计),OOP(面向对象编程)。

类与对象

1 类与对象是面向对象中的最基础的组成单元。类是共性的集合,对象是某一个性的产物。
2 类用于描述对象的结构, 例如每个人的名字、年龄等一系列特征。类除了包含特征(属性)外,还包括许多行为(方法)。根据这个类产生的对象都具有相同的行为。
3 对象所拥有的行为由类决定,无法执行超出类定义范畴的操作。
4 综上所述,类是对象的模版,但类无法直接使用,必须通过实例对象来使用。对象是由类产生的。

类与对象的定义及使用

1.定义类使用class class_name {}语句完成。类的组成:
(1)field(属性,成员,变量):一堆变量的集合;
(2)method(方法,行为):由对象调用。
范例:定义类

package com.java.entity;
public class Book {
   // 定义属性
   public String title;
   public double price;
   // 定义方法
   public void getInfo(){
       System.out.println("书名:" + title + ",价格:" + price);
   }
}

2.要使用类,必须要有对象,对象定义的语法有如下两种:
(1)声明并实例化对象:class_name object_name = new class_name()
(2)分步完成: 第一步-声明对象:class_name object_name = null;
第二部-实例化对象:object_name =new class_name();
引用数据类型与基本数据类型最大区别是需要内存的开辟及使用,所以关键字new的主要功能就是开辟内存空间。
3.当一个对象实例化后,利用如下方式操作类:
(1)object_name.field:操作类中的属性;
(2)object_name.method():调用类中的方法。
范例:使用类

public class Demo {
    public static void main(String[] args) {
        Book book = new Book(); // 声明并实例化对象
        book.title = "Java开发"; // 定义属性
        book.price = 66.6;
        book.getInfo(); // 调用方法
    }
}

4.堆内存和栈内存的概念:

堆内存 栈内存
保存对象的属性内容,使用关键字new开辟 栈内存:保存堆内存的地址。可以理解为栈内存保存对象的名字

无法加载
范例:分步使用实例化对象

public class Demo {
    public static void main(String[] args) {
        Book book = null; // 声明对象
        book = new Book(); // 实例化对象
        book.title = "Java开发";
        book.price = 66.6;
        book.getInfo();
    }
}

内存分析:使用关键字new开辟了新的的堆内存,堆内存中保存类定义的属性,此时所有的属性值都为默认值
无法加载
使用未实例化的对象,程序运行时会出现“NullPointerException(空指向异常)”

对象引用分析

1.在引用分析中,每次使用new关键字便会开辟新的堆内存。假设声明了两个对象,且都用new分别进行了实例化,那么两个对象占据的是不同的堆内存,因此不会互相影响。
范例:声明两个对象

public class Demo {
   public static void main(String[] args) {
       Book bkA = new Book();
       Book bkB = new Book();
       bkA.title = "Java开发";
       bkA.price = 66.6;
       bkA.getInfo();
       bkB.title = "C++开发";
       bkB.price = 22.6;
       bkB.getInfo();
   }
}

无法加载
2. 范例:对象引用传递

public class Demo {
    public static void main(String[] args) {
        Book bkA = new Book();
        Book bkB = null;
        bkA.title = "Java开发";
        bkA.price = 66.6;
        bkA.getInfo(); // 66.6
        bkB = bkA; // 引用传递
        bkB.price = 90.5;
        bkA.getInfo(); // 90.5
        bkB.getInfo(); // 90.5
    }
}

无法加载
由于两个对象指向同一块堆内存,所以任意一个对象修改了堆内存的属性值后,都会影响到其他对象的值。在引用中,一块堆内存可以被多个栈内存指向,但一个栈内存只能保存一个堆内存的地址。
3. 范例:引用传递

public class Demo {
    public static void main(String[] args) {
        Book bkA = new Book();
        Book bkB = new Book();
        bkA.title = "Java开发";
        bkA.price = 66.6;
        bkB.title = "C++开发";
        bkB.price = 90.5;
        bkB = bkA; // 引用传递
        bkB.price = 100;
        bkA.getInfo(); // 100
        bkB.getInfo(); // 100
    }
}

无法加载
通过内存分析可知,在引用时,一块没有栈内存指向的堆内存将成为垃圾,最后被垃圾收集器(GC)回收,回收后,释放其所占空间。

封装性

public class Demo {
    public static void main(String[] args) {
        Book bkA = new Book();
        bkA.title = "Java开发";
        bkA.price = -66.6;
        bkA.getInfo();
    }
}

上述代码没有语法错误,但存在业务逻辑错误,因为书的价格不能为负数。造成该问题是因为对象可以在类的外部直接访问属性。
1.因此应将Book类的属性设为对外不可见(只允许本类访问),可以使用private关键字定义属性。

public class Book {
    private String title;
    private double price;
    public void getInfo(){
        System.out.println("书名:" + title + ",价格:" + price);
    }
}

public class Demo {
    public static void main(String[] args) {
        Book bkA = new Book();
        bkA.title = "Java开发"; // 报错,无法访问私有属性
    }
}

此时外部对象无法直接调用类中的属性,但程序要正常执行,必须让对象可以操作类中的属性。因此在开发中,对于属性有该要求:类中的属性要使用private声明,如果属性需被外部使用,按照要求定义对应的setter()/getter().
2. 以Book类中的title属性为例,定义setter()/getter():

setter() getter()
作用 设置属性值 取得属性值
语法 public void setTitle(String t) public void getTitle()
是否含参 有参 无参
package com.java.entity;
public class Book {
    private String title;
    private double price;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public void getInfo(){
        System.out.println("书名:" + title + ",价格:" + price);
    }
}

如果要添加如价格不能为负数的功能,应在setter()中添加:

public void setPrice(double price) {
    if (price > 0.0){
        this.price = price; 
    }
}

对于数据的验证,开发中应有其他辅助代码完成,setter()只是简单地设置数据,getter()只用于返回数据。

构造方法与匿名对象

定义对象的语法:类名称 对象名称 = new 类名称();
①类名称:定义对象的类型;
②对象名称:标识符,要使用对象,需要有一个对象名;
③new:用于开辟堆内存空间,实例化对象;
④类名称():一个方法名和类名称一样的方法,这就是构造方法。
通过上述分析,我们发现了构造方法的存在,但我们并没有定义构造方法。之所以能使用这个构造方法,是因为Java默认在没有自定义构造方法的情况下,程序编译时自动在类中添加一个无参无返回值的构造方法。
1.构造方法的定义原则:方法名称与类名称相同,没有返回值。

class Book {
    public Book() { // 系统自动生成的构造方法
    }
}

2.构造方法在对象使用new实例化时调用。
范例:证明构造方法被调用

public class Book {
   public Book() {
       System.out.println("构造方法被调用");
   }
}

public class Demo {
   public static void main(String[] args) {
       Book book = null ; // 声明对象
       book = new Book(); // 实例化对象时调用构造方法
       //结果:构造方法被调用
   }
}

构造方法与普通方法的最大区别:构造方法只在实例化对象时调用一次。普通方法在对象实例化后可以多次调用。
3.范例:自定义构造方法

class Book {
    private String title;
    private double price;
    // 自定义构造方法后,系统不再自动生成无参无返回值的构造方法
    public Book(String t, double p) {
        title = t;
        price = p;
    }

    public void getInfo() {
        System.out.println("书名:" + title + ",价格:" + price);
    }
}

public class Demo {
    public static void main(String[] args) {
        Book book = new Book("Java开发", 66.6);
        book.getInfo();
    }
}

由上述代码可知构造方法的作用:在类对象实例化时设置属性的初始值,即构造方法用于属性初始化
4.构造方法也属于方法,因此可以进行重载。
范例:构造方法重载

class Book {
    public Book() {
        System.out.println("系统自动生成的构造方法");
    }
    // 进行方法重载的构造方法
    public Book(String t, double p) {
        System.out.println("方法重载后的构造方法");
    }
}

public class Demo {
    public static void main(String[] args) {
        Book bookA = new Book(); // 系统自动生成的构造方法
        Book bookB = new Book("Java开发", 66.6); // 方法重载后的构造方法
    }
}

重载方法时要求:按照参数个数,对方法进行升序或者降序排列。
5.在定义类时可为属性设置默认值。但该默认值只有在对象实例化后才进行设置。而对象实例化是对象构造的最后一步。对象实例化过程的步骤:类的加载,内存的分配,默认值的设置,构造方法

class Book {
    private String title = "Java开发"; // 设置默认值
    private double price;

    public Book() {
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        if (price > 0.0){
            this.price = price;
        }
    }

    public void getInfo() {
        System.out.println("书名:" + title + ",价格:" + price);
    }
}

public class Demo {
    public static void main(String[] args) {
        Book bkA = new Book();
        bkA.getInfo(); // 书名:Java开发,价格:0.0
    }
}

本程序中,只有在对象实例化后,才会将”Java开发”设置给title属性。在没有实例化前,title的值仍为其数据类型的默认值,即null。真实的对象信息都保存在堆内存中。
6.匿名对象:没有栈内存指向的对象,即没有标识符的对象

public class Demo {
    public static void main(String[] args) {
        new Book("Java开发",6.6).getInfo();
    }
}

由于匿名对象没有标识符,也没有其他对象对其引用,因此只能使用一次,之后该对象空间变为垃圾,等待回收。
何时使用匿名对象:但一个对象仅需要被使用一次时就使用匿名对象。当一个对象要被反复调用时,就使用非匿名对象。

简单Java类实践

题目要求:定义一个雇员类,类中有雇员编号、姓名、职位、基本工资、佣金等属性。
提示:这种类被称为简单java类,因为这种类不包含过于复杂的程序逻辑。

对于简单Java类而言,它的要求如下:
·类名必须有意义;
·类中所有属性必须private封装,封装后的属性必须提供setter和getter方法;
·类中可以有多个构造方法,但必须保留无参构造方法;
·类中不允许出现输出语句,信息输出必须交给调用处。
·类中需要提供有一个取得对象完整信息的方法,暂定为getInfo(),返回值类型为String型。

第一步:定义类

public class Emp {
    private int eId; // 编号
    private String eName; // 姓名
    private String job; // 职位
    private double sal; // 工资
    private double comm; // 佣金
    // 定义构造方法
    public Emp() {
    }
    
    public Emp(int eId, String eName, String job, double sal, double comm) {
        this.eId = eId;
        this.eName = eName;
        this.job = job;
        this.sal = sal;
        this.comm = comm;
    }
    // 定义setter和getter方法
    public int geteId() {
        return eId;
    }

    public void seteId(int eId) {
        this.eId = eId;
    }

    public String geteName() {
        return eName;
    }

    public void seteName(String eName) {
        this.eName = eName;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public double getComm() {
        return comm;
    }

    public void setComm(double comm) {
        this.comm = comm;
    }
    // 定义普通方法
    public String getInfo() {
        return "编  号" + this.eId + "\n" +
                "姓 名" + this.eName + "\n" +
                "职 位" + this.job + "\n" +
                "工 资" + this.sal + "\n" +
                "佣 金" + this.comm;
    }
}

第二步:测试

public class TEmp {
    public static void main(String[] args) {
        Emp e = new Emp(1, "Tom", "保安", 800.0, 10.0);
        System.out.println(e.getInfo()); // 获取全部信息
        System.out.println(e.geteId()); // 通过getter()获取单一信息
    }
}

类中的setter()/getter()必须写。setter()除了有设置属性内容功能外,还有修改属性值的功能。

This blog is under a CC BY-NC-SA 3.0 Unported License
本文链接:http://yov.oschina.io/article/Java/Java Base/Java基础知识(三)/